﻿// <copyright file="ServerConnect.cs" company="Soumya Chattopadhyay">
// Copyright (c) 2010 All Right Reserved
// </copyright>
// <disclaimer> This software is intented for educational purposes only and not for 
// commerical or prodution use. The software is provided "as is", without warranty 
// of any kind, express or implied, including but not limited to the warranties of 
// merchantability, fitness for a particular purpose and noninfringement. In no event 
// shall the author(s) or copyright holder(s) be liable for any claim, damages or other 
// liability, whether in an action of contract, tort or otherwise, arising from, out of 
// or in connection with the software or the use or other dealings in the software.
// </disclaimer>

namespace My.CodePlex.TFSExplorer
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Web.Services.Protocols;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Threading;
    using Microsoft.TeamFoundation;
    using Microsoft.TeamFoundation.Client;
    using Microsoft.TeamFoundation.Proxy;
    using Microsoft.TeamFoundation.Server;
    using Microsoft.TeamFoundation.VersionControl.Client;
    using My.CodePlex.TFSExplorer.Resources;
    using My.CodePlex.TFSExplorer.TeamFoundation;

    /// <summary>
    /// Connect to the TFS server
    /// </summary>
    public class ServerConnect
    {
        #region Fields

        /// <summary>
        /// The background thread that connects to the TFS server
        /// </summary>
        private Thread connectToServer;

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the ServerConnect class
        /// </summary>
        public ServerConnect()
        {
            // Setup the background thread
            this.connectToServer = new Thread(this.ConnectToServer_DoWork);
            this.connectToServer.SetApartmentState(ApartmentState.STA);
        }

        #endregion

        #region Events

        /// <summary>
        /// Notify the parent control when finished
        /// </summary>
        public event Action<object> OnPopulateEnd;

        /// <summary>
        /// Notify the parent that the control
        /// has starting populating itself
        /// </summary>
        public event Action<object> OnPopulateStart;

        #endregion

        #region Public Methods

        /// <summary>
        /// Connect to the TFS server
        /// </summary>
        /// <param name="dispatcher">The UI dispatcher</param>
        public void Connect(System.Windows.Threading.Dispatcher dispatcher)
        {
            // Display the built-in domain picker dialog
            DomainProjectPicker domainProjectPicker = new DomainProjectPicker(DomainProjectPickerMode.None);

            if (domainProjectPicker.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                // Let parent know that control is starting connection
                if (this.OnPopulateStart != null)
                {
                    this.OnPopulateStart(domainProjectPicker.SelectedServer.Name);
                }
                
                // Try to connect to the TFS server
                this.connectToServer.Start(new BackgroundThreadArg()
                {
                    ServerName = domainProjectPicker.SelectedServer.Name,
                    UIDispatcher = dispatcher
                });
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// The background thread's work
        /// </summary>
        /// <param name="data">The server name</param>
        private void ConnectToServer_DoWork(object data)
        {
            BackgroundThreadArg arg = data as BackgroundThreadArg;

            UICredentialsProvider cred = new UICredentialsProvider();

            // Connect to the TFS server
            TeamFoundationServer tfsServer = new TeamFoundationServer(arg.ServerName, cred);
            if (tfsServer == null)
            {
                MessageBox.Show(string.Format(Resource.ServerConnectNotRegisteredError, arg.ServerName));
                return;
            }

            // Authenticate the TFS server
            bool authenticated = this.AuthenticateToTFSServer(tfsServer);
            if (!authenticated)
            {
                return;
            }

            Dispatcher dispatcher = arg.UIDispatcher;

            // Save the authenticated TFS context
            try
            {
                TeamFoundationContext teamFoundationContext = new TeamFoundationContext(tfsServer);
                dispatcher.Invoke((Action)(() => this.OnPopulateEnd(teamFoundationContext)));
            }
            catch (Exception ex)
            {
                dispatcher.Invoke((Action)(() => MessageBox.Show(ex.Message)));
                dispatcher.Invoke((Action)(() => this.OnPopulateEnd(ex.Message)));
            }
        }

        /// <summary>
        /// Authenticate the TFS server
        /// </summary>
        /// <param name="tfsServer">The TFS server name</param>
        /// <returns>True is authenticated</returns>
        private bool AuthenticateToTFSServer(TeamFoundationServer tfsServer)
        {
            // Authenticate to the Hamelin TFS server
            // using default credentials
            try
            {
                tfsServer.Authenticate();
            }
            catch (SoapException ex)
            {
                MessageBox.Show(ex.Message, Resource.ProductNameLong, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            catch (TeamFoundationServerUnauthorizedException ex)
            {
                MessageBox.Show(ex.Message, Resource.ProductNameLong, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }

            if (!tfsServer.HasAuthenticated)
            {
                MessageBox.Show(string.Format(Resource.ServerConnectAuthenticationFailedError, tfsServer.Name), Resource.ProductNameLong, MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }

            return true;
        }

        /// <summary>
        /// Find the TFS server in the registered servers list
        /// on the user's machine
        /// </summary>
        /// <param name="tfsServerName">The server name string</param>
        /// <returns>The matching server object</returns>
        private TeamFoundationServer FindRegisteredServer(string tfsServerName)
        {
            // Find the Hamelin TFS server
            TeamFoundationServer[] registeredTFSServers = RegisteredServers.GetServers();
            TeamFoundationServer matchingServer = null;

            foreach (var tfsServer in registeredTFSServers)
            {
                if (string.Equals(tfsServer.Name, tfsServerName))
                {
                    matchingServer = tfsServer;
                    break;
                }
            }

            return matchingServer;
        }

        #endregion

        #region Private Classes

        /// <summary>
        /// Private class that represents the argument passed to the background thread
        /// </summary>
        private class BackgroundThreadArg
        {
            /// <summary>
            /// Gets or sets the server name
            /// </summary>
            public string ServerName { get; set; }

            /// <summary>
            /// Gets or sets the UI dispatcher
            /// </summary>
            public Dispatcher UIDispatcher { get; set; }
        }

        /// <summary>
        /// Private class that represents the result of the background thread call
        /// </summary>
        private class BackgroundThreadResult
        {
            /// <summary>
            /// Gets or sets a value indicating whether the thread succeeded
            /// </summary>
            public bool Succeeded { get; set; }

            /// <summary>
            /// Gets or sets the authenticated TFS context
            /// </summary>
            public TeamFoundationContext TFSContext { get; set; }
        }

        #endregion
    }
}
